package cn.com.zcode.core.dao;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.ReplicationMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Example;

import cn.com.zcode.core.model.BaseModelSupport;


public class BaseHibernateDaoSupport implements BaseDao {

	private static final String WHERE = "where";
	private static final String ORDERBY = "order by";
	private Logger logger = Logger.getLogger(BaseHibernateDaoSupport.class);
	private SessionFactory sessionFactory;

	
	protected Query setParameter(Query query, Map<String, Object> map) {
		if (map != null) {
			Set<String> keySet = map.keySet();
			for (String string : keySet) {
				Object obj = map.get(string);
				if(obj instanceof Collection<?>){
					query.setParameterList(string, (Collection<?>)obj);
				}else if(obj instanceof Object[]){
					query.setParameterList(string, (Object[])obj);
				}else{
					query.setParameter(string, obj);
				}
			}
		}
		return query;
	}
	
	public <M extends BaseModelSupport> M save(M t) {
		logger.debug("save ...." + t);
		getSession().saveOrUpdate(t);
		logger.debug("save successful");
		return t;
	}

	public <M extends BaseModelSupport> void edit(M t) {
		logger.debug("edit ...." + t);
		this.getSession().update(t);

	}

	public void delete(String id, Class<? extends BaseModelSupport> zlass) {
		logger.debug("delete ...." + id);

	}

	public <M extends BaseModelSupport> void delete(M persistentInstance) {
		logger.debug("deleting User instance");
		getSession().delete(persistentInstance);
	}

	@SuppressWarnings("unchecked")
	public <M extends BaseModelSupport> M get(String id, Class<M> mlass) {
		logger.debug("get ...." + id);
		return (M) this.getSession().get(mlass, id);
	}

	// public <O> O getByHQL(String hql, Class<O> mlass) {
	// Query queryObject = getSession().createQuery(hql);
	// return (O) queryObject.uniqueResult();
	// }
	@SuppressWarnings("unchecked")
	public <O> O getByHQL(String hql, Class<O> zlass, Object... parm) {
		Query queryObject = getSession().createQuery(hql);
		if (parm != null && parm.length > 0) {
			for (int i = 0; i < parm.length; i++) {
				queryObject.setParameter(i, parm[i]);
			}
		}
		return (O) queryObject.uniqueResult();
	}

	@SuppressWarnings("unchecked")
	public <M extends BaseModelSupport> List<M> findByExample(M instance) {
		logger.debug("finding  instance by example");
		Criteria criteria = getSession().createCriteria(instance.getClass());
		criteria.add(Example.create(instance));

		List<M> results = criteria.list();
		logger.debug("find by example successful, result size: " + results.size());
		return results;
	}

	@SuppressWarnings("unchecked")
	public <M extends BaseModelSupport> List<M> findByProperty(String propertyName, Object value, Class<M> zlass) {
		logger.debug("finding  instance with property: " + propertyName + ", value: " + value);
		String queryString = "from " + zlass.getSimpleName() + " as model where model." + propertyName + "= ?";
		Query queryObject = getSession().createQuery(queryString);
		queryObject.setParameter(0, value);
		return queryObject.list();
	}

	public <M extends BaseModelSupport> List<M> findAll(Class<M> zlass) {
		return this.findAll(null, null, zlass);
	}
	@SuppressWarnings("unchecked")
	public <M extends BaseModelSupport> List<M> findAll(String[] orders, String[] wherecond, Class<M> zlass) {
		logger.debug("finding all  instances");
		StringBuffer queryString = new StringBuffer("from " + zlass.getSimpleName());
		queryString = this.appendHql(queryString, wherecond, WHERE);
		queryString = this.appendHql(queryString, orders, ORDERBY);
		logger.info("HQL:"+queryString);
		Query queryObject = getSession().createQuery(queryString.toString());
		return queryObject.list();
	}

	@SuppressWarnings("unchecked")
	public <M extends BaseModelSupport> List<M> findByHQL(String hql, Class<M> zlass) {
		Query query = this.getSession().createQuery(hql);
		return query.list();
	}

	@SuppressWarnings("unchecked")
	public  <M extends BaseModelSupport> List<M> findByHQL(String hql, Class<M> zlass, Object... parm) {
		Query queryObject = getSession().createQuery(hql);
		if (parm != null && parm.length > 0) {
			for (int i = 0; i < parm.length; i++) {
				queryObject.setParameter(i, parm[i]);
			}
		}
		return queryObject.list();
	}

	@SuppressWarnings("unchecked")
	public <M extends BaseModelSupport> M merge(M detachedInstance) {
		logger.debug("merging User instance");
		M result = (M) getSession().merge(detachedInstance);
		logger.debug("merge successful");
		return result;
	}

	public <M extends BaseModelSupport> void saveOrUpdate(M instance) {
		logger.debug("attaching dirty  instance");
		getSession().saveOrUpdate(instance);
		logger.debug("attach successful");
	}

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	public Session getSession() {
		return sessionFactory.getCurrentSession();
	}

	private StringBuffer appendHql(StringBuffer sb, String[] parm, String perfix) {
		if (parm != null && perfix != null) {
			StringBuffer cond = null;
			for (String string : parm) {
				if (!string.isEmpty()) {
					if (cond == null) {
						cond = new StringBuffer();
					}
					cond.append(" ");
					cond.append(string);
				}
			}
			if (cond != null) {
				sb.append(" ");
				sb.append(perfix);
				sb.append(cond);
			}
		}
		return sb;

	}

	@Override
	public <M extends BaseModelSupport> M saveWithId(M instance) {
		 this.getSession().replicate(instance, ReplicationMode.EXCEPTION);
		return instance;
	}

}
